/**
 * 远光Gris平台3.0版本 http://www.ygsoft.com/
 *
 * 页面间消息发送.
 *
 * 使用方式：
 *    1. 在发送者和接收者所在的页面同时引入此JS文件；
 *    2. 发送者发送消息方式：
 *       --参数1：消息标识（字符串）；
 *       --参数2：消息内容（可以是任何对象）
 *       pagemessage.send("type1","hello world!");
 *       发送者并不关心消息发送给了谁、在哪里、如何处理。
 *    3. 接收者注册到消息队列的方式：
 *       --参数1：数组或字符串。可接收的消息类型集合，为“*”表示接收所有消息；
 *       --参数2：函数。接收消息时的处理函数；
 *       --参数3：可选。发送者所在的窗体。
 *                为空表示当前窗体作为发送者；
 *                为url表示与URL匹配的页面作为发送者;
 *                为函数表示由此函数返回发送者窗体。
 *                为*表示接收任何窗体发送的消息
 *       pagemessage.register(["type1","type2"],function(source,type,content){
 *          //   source:发送者窗体对象
 *          //   type:消息标志
 *          //   content:消息内容。任何对象
 *       },'menuTree.html?param1=111');
 *
 * 将消息发送给门户主页的方法
 *   pagemessage.send(PageMessage.EXECSCRIPT,function(source,type,content){
*      //在门户主页弹出窗体
*      //请不要在此有依赖特定作用域的代码
*   });
 *
 */

define(["jquery"],function($){

    // 日志对象
    var log = window.console;

    /**
     消息监听者集合.
     集合中对象的属性：
     --types：可接收的消息类型集合
     --method：接收消息时的处理方法体
     --senderWindow 发送者所在的窗体
     --observerWindow 观察者所在的窗体
     */
    if(!window.observers){
    	window.observers=new Array();
    }
    var observers = window.observers;
    /**
     * 通过URL全局寻找窗体.
     * @param {String} url
     * @return {Object} 窗体对象
     */
    var findWinByUrl = function(url) {
        //注意：url = abcc.jsp 可匹配:abcc.jsp和abcc.jsp?param1=1&param2=1
        var allWins = allWin();
        var retWins = [];
        var j = 0;
        for(var i =0;i<allWins.length;i++) {
            try{
                if(matchUrl(allWins[i].location.href,url)) {
                    retWins[j++] = allWins[i];
                }
            }catch(e){}
        }
        return retWins;
    };

    /**
     * 匹配两个URL是否属于一个页面,URL的查询字符串部分不做考虑
     *
     * @param {String} targetUrl 目标URL
     * @param {String} sourceUrl 源URL
     * @return {Boolean} 是否匹配成功
     */
    var matchUrl = function(targetUrl,sourceUrl) {
        var targetUrls = targetUrl.split("?");
        var sourceUrls = sourceUrl.split("?");
        //1. 匹配文件路径
        if(targetUrls[0].lastIndexOf(sourceUrls[0]) !=-1) {
            //2. 匹配查询字符串(暂不支持)
            return true;
        }else {
            return false;
        }
    };
    /**
     * 获得发送者所在的窗体.
     * @param {Object | null | String | Function} senderWindow
     * @returns {Object} 窗体对象
     */
    var getSenderWindow = function(senderWindow) {
        if(senderWindow == null) {
            return window;
        } else if(typeof(senderWindow) == 'function') {
            return senderWindow();
        } else if(typeof(senderWindow) == 'string' && senderWindow != "*") {
            return findWinByUrl(senderWindow);
        }
        return senderWindow;
    };
    /**
     * 校验发送消息的窗体
     * @param {Object | null | String | Function} senderWindow
     * @param {Object} 目标窗体
     * @returns {Boolean}
     */
    var matchSendWindow = function(senderWindow,targetWin) {
        var sWins = [];
        var sWins =  getSenderWindow(senderWindow);
        if(! (sWins instanceof Array)) {
            sWins = [sWins];
        }
        for(var i = 0;i<sWins.length;i++) {
            if(sWins[i] == targetWin)
                return true;
        }
    }

    /**
     * 获得页面所有窗体对象.
     * @param {Object} win 窗体对象，调用时不输入
     * @param {Object[]}
     */
    var allWin = function(win) {
        var ret = [];
        if(win == null) {
            win = window;
            while(win.parent != win) {
                win = win.parent;
            }
            ret[0] = win;
        }
		try{
			//2. 递归匹配下级frames
	        for(var i = 0;i<win.frames.length;i++) {
	        	if(win.frames[i].location.href!="about:blank"){
		            ret[ret.length] = win.frames[i];
		            var ret1 = allWin(win.frames[i]);
		            if(ret1 && ret1.length > 0) {
		                ret = ret.concat(ret1);
		            }
	            }
	        }
		}catch(e){
			window.console.error(e.message);
		}
        return ret;
    };
    //发布的方法
    var pageMessage = {
        /**
         * 注册消息接收者
         * @param {String | Array} types 可接收的消息类型集合
         * @param {Function} method 接收消息时的处理方法体
         * @param {Object} senderWindow 可选（为空表当前窗体）。发送者所在的窗体
         * @param {Object} observerWindow 可选（为空表当前窗体）。观察者所在的窗体
         * @param {Number} sortIndex 排序号。可选 共享模式有效。大数字在前,为空在后。
         */
        register : function(types,method,senderWindow,observerWindow,sortIndex) {
        	log && log.info("消息注册："+types);
            if(senderWindow == null) {
                senderWindow = window;
            }
            if(observerWindow == null) {
                observerWindow = window;
            }

            if(typeof types == 'string') {
                types = [types];
            }

            var observer = {types:types,method:method,senderWindow:senderWindow,observerWindow:observerWindow,sort:sortIndex};
            observers.push(observer);
        },
        /**
         * 卸载消息接收者.
         * @param {Array} types 可接收的消息类型集合
         * @param {Object} senderWindow 可选（为空表当前窗体）。发送者所在的窗体
         * @param {Object} observerWindow 可选（为空表当前窗体）。观察者所在的窗体
         */
        unRegister : function(types,senderWindow,observerWindow) {
        	log && log.info("消息注销："+types);
            if(senderWindow == null) {
                senderWindow = window;
            }
            if(observerWindow==null){
            	observerWindow=window;
            }
            if(typeof types == 'string') {
                types = [types];
            }

            for(var i=0;i<observers.length;i++) {
                //按types逐一删除匹配成功的元素
                if(observers[i].senderWindow == senderWindow && observers[i].observerWindow == observerWindow) {
                    for(var j=0;j<types.length;j++) {
                        for(var n=0;n<observers[i].types.length;n++) {
                            if(types[j] == observers[i].types[n]) {
                                delete observers[i].types[n];                                
                            }
                        }
                    }
                }

                //删除观察者
                try {
                    var delFlag=false;
                    if(!observers[i].types){
                    	delFlag=true;
                    }
                    if(delFlag) {
                        delete observers[i];
                        observers.remove(observers[i]);
                    }
                }catch(e){};
            }
        }
        /**
         * 发送消息.
         * @param {String} type 消息标识
         * @param {Object} content 消息内容
         */
        ,send : function(type,content) {
        	log && log.info("消息发送："+type);
            //广播给观察者
            //遍历消息监听者，调用消息监听者的接受消息函数
            var allObs = [];
            var allWins = allWin();
            for(var t=0;t<allWins.length;t++) {
                try {
                    var win = allWins[t];
                    var obs = this.getObservers();
                    if(obs !=null && obs.length > 0 ) {
                        allObs = allObs.concat(obs);
                    }
                }catch(e){
                }
            }

            //按sort DESC排序
            var t;
            for(var i =0;i<allObs.length-1;i++) {
                for(var j=i+1;j<allObs.length;j++) {
                    if(allObs[j].sort > allObs[i].sort || (allObs[j].sort != null && allObs[i].sort == null)) {
                        t = allObs[i];
                        allObs[i] = allObs[j];
                        allObs[j] = t;
                    }
                }
            }

            for (var i=0;i<allObs.length;i++){
                //获得观察者”关注“的发送者
                try {
                    var flag = false;
                    if(allObs[i].senderWindow == "*") {
                        flag = true;
                    } else {
                        flag = matchSendWindow(allObs[i].senderWindow,window);
                    }

                    for(var j=0;flag && j<allObs[i].types.length;j++) {
                        //a. 当前发送者和观察者”关注“的发送者相同
                        //b. 消息标识匹配
                        if(allObs[i].types[j] == "*" || allObs[i].types[j] == type) {
                            //注意作用域
                            try {
                                var _continue = allObs[i].method.call(allObs[i].observerWindow,window,type,content);
                                //当观察者处理函数返回false,表示处理链的后续节点不再执行。
                                if(_continue == false) {
                                    return;
                                }
                            }catch(e) {
                                log && log.info("观察者失效（可能是页面刷新导致）：" +e.message);
                            }
                        }
                    }
                }
                catch(e) {
                    log && log.error(e.message);
                }
            }
        },
        /**
         * 获取消息监听者
         * @returns {Array}
         */
        getObservers : function() {
            return observers;
        }
    };
    return pageMessage;
});
